4  Cálculo de CCM para una cadena quiral C3

from pylab import *
import plotly.graph_objects as go
import functools
import itertools

En este capítulo se estudiará la quiralidad de los modos normales de una cadena quiral con simetría \(C_{3}\). Los criterios usados son la polarización de fonón, el CCM y el pseudoescalar de momento angular.

Debajo, se definen varias constantes a emplear. Dentro de estas están las masas de los sitios, la longitud de los lados del ángulo vista desde arriba, las constantes de resorte y el ángulo de los enlaces respecto al plano x - y. Además, se definen las posiciones los tres átomos dentro de la celda unitaria, y dos átomos de celdas vecinas. También, se defienen dos rotaciones que serán usadas de forma constante.

# Masas de los distintos sitios. 
m1 = 1
m2 = 1
m3 = 1

M = [m1,m2,m3]

# Matriz de resortes a lo largo de x.
KL = 1
KT1 = 0.05
KT2 = 0.25

# Tensor de constante de red en configuración usual. 
Kx = array([[KL,0,0],
              [0,KT1,0],
              [0,0,KT2]],dtype=complex)

# Longitud de los enlaces proyectados al plano
a = 1

# Ángulo de los enlaces respecto al plano x - y.
φxy = pi/3

# Longitud de la celda unitaria.
c = 3 * a * tan(φxy)

avec = array([0,0,c])

#Rotación de φ respecto al plano x - y.
def T(φ):
  return array([[cos(φ) ,0.  ,sin(φ)],
                [0.     ,1.  ,0],
                [-sin(φ),0.  ,cos(φ)]])

                #Rotación respecto al eje z.
def U(θ):
  return array([[cos(θ),-sin(θ),0],
              [sin(θ),cos(θ),0],
              [       0,      0,1]] )


# Posiciones de los átomos en la celda unitaria de la cadena.
r1 = array([1,0,0])
r2 = dot(U(2*pi/3),r1) + array([0,0,c/3])
r3 = dot(U(4*pi/3),r1)+ array([0,0,2*c/3])

# Posición de los átomos en la celda vecina. 
r1plus = r1 + avec
r3minus = r3 - avec

positions = array([r1,r2,r3])

positionsnn = array([r3minus,r1plus])

X,Y,Z = positions.T
Xnn,Ynn,Znn = positionsnn.T

Debajo, se muestra una imagen de la cadena.

DATA = [go.Scatter3d(x=X, y=Y, z=Z,mode='markers',marker_color = "blue",showlegend=False)]

DATA.append(go.Scatter3d(x=Xnn, y=Ynn, z=Znn,mode='markers',marker_color = "red",showlegend=False))

DATA.append(go.Scatter3d(x= [X[0],Xnn[0]], y=[Y[0],Ynn[0]], z=[Z[0],Znn[0]],mode='lines',line=dict(color='red'),showlegend=False))

DATA.append(go.Scatter3d(x= [X[0],X[1]], y=[Y[0],Y[1]], z=[Z[0],Z[1]],mode='lines',line=dict(color='blue'),showlegend=False))

DATA.append(go.Scatter3d(x= [X[2],X[1]], y=[Y[2],Y[1]], z=[Z[2],Z[1]],mode='lines',line=dict(color='blue'),showlegend=False))

DATA.append(go.Scatter3d(x= [X[2],Xnn[1]], y=[Y[2],Ynn[1]], z=[Z[2],Znn[1]],mode='lines',line=dict(color='red'),showlegend=False))
fig = go.Figure(data=DATA)
fig.show()

4.1 Cálculo de CCM de la estructura

Para calcular el CCM de la estructura se sigue la definición del capítulo pasado. Sin embargo, para hacer este cálculo sólo se consideran reflexiones por planos que contengan al eje z. Esto pues sólo nos interesa la quiralidad respecto a este eje. Aún así, se define una rotación respecto al plano x - y que será utilizada más adelante en el cálculo de la matriz dinámica.

r2 - dot(U(2*pi/3),r1)
array([0.        , 0.        , 1.73205081])

También se definen la matriz identidad en 3D y una reflexión respecto al plano xz. Además, se define una funciín que transforma operadores. Esta función se usará para rotar el plano respecto al cual se realiza la rotación.

#Matriz identidad.
Id = array([[1,0,0],
            [0,1,0],
            [0,0,1]] )

#Reflexión respecto al plano x - z.
σy = array([[-1,0,0],
            [0,1,0],
            [0,0,1]] )

def TensT(O,A):
  """Función que aplica transforma por un operador O a un tensor A."""
  return dot( inv(O), dot(A,O) )

Ya con todas las funciones a usar bien definidas, se hace el cálculo de la CCM De la estructura. Para ello, primero se calculan las coordenadas respecto al centro de masa.

# Centro de masa
RCM = (m1*r1 + m2*r2 + m3*r3)/(m1 + m2 + m3)

# Coordenada Relativa 1
qrcm1 = sqrt(m1)*(r1 - RCM)

# Coordenada Relativa 2
qrcm2 = sqrt(m2)*(r2 - RCM)

# Coordenada Relativa 3
qrcm3 = sqrt(m3)*(r3 - RCM)

# Lista con las coordenadas relativas. 
Qrcm = [qrcm1,qrcm2,qrcm3]

Queremos calcular la CCM tal que el plano de inversión elegido maximize la superposición de la estructura con la estructura invertida. Para ello, se define una función que calcula el CCM de la estructura tomando una reflexión respecto a un plano de entrada.

def CCMS(σ):
    num = 0
    den = 0
    for q in Qrcm:
        num = num + dot(q,dot(Id + σ,q))
        den = den + dot(q,q)
    return 1 - (num/(2*den))

Ya hecho esto, se calcula el CCM de la estructura. Notamos que para esta cadena el CCM es igual sin importar que plano de reflexión se use. Esto se ve en la gráfica mostrada debajo.

θ = linspace(0,pi,300)

σ = []

for ang in θ:
    σ.append(TensT(U(ang),σy))
σ = array(σ)

CCM_estructura = []

for ref in σ:
    CCM_estructura.append(CCMS(ref))

print("La CCM de la estructura es", str(np.min(CCM_estructura)))
La CCM de la estructura es 0.16666666666666663
Labels = [r"0",r"π/2",r"π"]
Ticks = concatenate([[0],[pi/2],[pi]])

fig,ax = plt.subplots(ncols=1,nrows=1,figsize=(6,4.5))
ax.plot(θ,CCM_estructura)
ax.set_xticks(Ticks)
ax.set_ylim([0,1])
ax.set_xticklabels(Labels,fontsize = 20);
ax.set_ylabel("CCM",fontsize = 20)
plt.show()

4.2 Cálculos del CCM de los modos vibracionales

Ahora calculamos el CCM asociado a los modos normales. Para ello, debemos también construir un programa que obtenga las frecuencias de dichos modos, así como una función que de el CCM de un modo dado.

Primero, se define una función que regresa el valor máximo del producto \(\langle Q| Q \rangle\) para cierto plano de reflexión. Además, se define una función que regresa el valor esperado y que será usada más adelante.

def expectedval(vec,S):
    return dot(np.conj(vec).T,dot(S,vec)).real

θ = linspace(0,pi,300)

def CCMMax(q):
    max = 0
    for ang in θ:
        σ = TensT(U(ang),σy)
        if abs(expectedval(q,Id + σ)) > max:
            max = abs(expectedval(q,Id + σ))
            M = expectedval(q,Id + σ)
    return M

Luego, se define la función que calcula las frecuencias de un modo normal para un punto del espacio recíproco dado.

def EigenfrequenciesC3(k):

  """Función que regresa las eigenfrecuencias para un vector recíproco kz dado."""

  #Se define el tensor de esfuerzos de todo el sistema.

  #Matriz con constante de fuerza considerando una rotación respecto al plano x - y.
  φxy = pi/3
  Kx2 = dot(T(φxy),dot(Kx,T(-φxy)))

  #Matrices de fuerza para cada uno de los vectores en la red.
  K23 = dot(U(pi),dot(Kx2,U(-pi)))     #Calculada tomando 2 como origen.
  K12 = dot(U(pi/3),dot(Kx2,U(-pi/3))) #Calculada tomando 1 como origen.
  K13 = dot(U(-pi/3),dot(Kx2,U(pi/3))) #Calculado tomando 3 como origen.

  DicMat   = { 0: (K12 + K13)/m1,
               1: -K12/sqrt(m1*m2),
               2: -K13/sqrt(m1*m3)*exp(-1J*k*c),
               3: -K12/sqrt(m1*m2),
               4: (K23+K12)/m2,
               5: -K23/sqrt(m2*m3),
               6: -K13/sqrt(m1*m3)*exp(1J*k*c),
               7: -K23/sqrt(m2*m3),
               8: (K23 + K13)/m3 }

  Dinteger = array([[0,1,2],
                    [3,4,5],
                    [6,7,8]])

  Dm = [ [DicMat[i] for i in rw] for rw in Dinteger ]
  Dynamical = asarray(np.bmat(Dm))

  ω2,eigvecs = eigh(Dynamical)

  return sqrt(abs2))/2/pi,eigvecs

Se definieron funciones que calculaba la polarización de fonón, la CCM y el pseudoescalar de momento angular dadas una frecuencia y un modo normal.

def CCM_general(ω,eigvecs):
  CCM = []
  for i in range(len(ω)):
    eigvec = eigvecs[:,i]
    q1 = sqrt(m1) * eigvec[0:3]
    q2 = sqrt(m2) * eigvec[3:6]
    q3 = sqrt(m3) * eigvec[6:]

    Q = [q1,q2,q3]

    num = 0
    den = 0

    for q in Q:
        num += CCMMax(q)
        den += vdot(q,q).real

    CCM.append(1 - (num/(2*den)))

  return CCM
# Primero se define una función que regresa el operador de polarización de fonón. 
def OperadorPseudomomento(n):

  Sz = array([[0,-1J,0],
              [1J,0,0],
              [0,0,0]],dtype=complex)

  return np.kron(np.eye(n,dtype=complex),Sz)

S = OperadorPseudomomento(3)

def Pol_general(ω,eigvecs):
  Pol = []
  for i in range(len(ω)):
    eigvec = eigvecs[:,i]
    Pol.append(expectedval(eigvec,S))

  return Pol
def Pz_general(ω,eigvecs):
  pzlist = []
  for i in range(len(ω)):
    eigvec = eigvecs[:,i]
    ω2 = ω[i]
    q1 = sqrt(m1) * eigvec[0:3]
    q2 = sqrt(m2) * eigvec[3:6]
    q3 = sqrt(m3) * eigvec[6:]

    Q = [q1,q2,q3]

    pz = 0

    for i in range(len(Q)):
        pz = pz + M[i]*Q[i][2]*(X[i]*Q[i][1] - Y[i]*Q[i][0]).real
    pzlist.append(pz)

  return pzlist

Finalmente, se muestra la gráfica de bandas para la cadena \(C_{3}\) junto con los respectivos valores de CCM en cada punto:

Kpoints = np.linspace(-pi/c,pi/c,500)

Klabels = [r"K/2",r"Γ",r"K/2"]
Kticks = concatenate([[0],[250],[500]])

BandasC3 = []
EigvecsC3 = []
CCMC3 = []
PolC3 = []
PzC3 = []

KevaluateC3 = (list( map(EigenfrequenciesC3,Kpoints) ))

for ω2,eigvec in KevaluateC3:
  BandasC3.append(ω2)
  EigvecsC3.append(eigvec)

for i in range(len(BandasC3)):
  CCMC3.append(CCM_general(BandasC3[i],EigvecsC3[i]))
  PolC3.append(Pol_general(BandasC3[i],EigvecsC3[i]))
  PzC3.append(Pz_general(BandasC3[i],EigvecsC3[i]))

CCMC3 = array(CCMC3)
BandasC3 = array(BandasC3)
PolC3 = array(PolC3)
PzC3 = array(PzC3)
numKC3,nbandsC3 = shape(BandasC3)
kenumC3 = arange(numKC3)

fig,ax = plt.subplots(ncols=1,nrows=1,figsize=(4.5,6))
for j in range(nbandsC3):
  graficaC3 = ax.scatter(kenumC3,BandasC3.T[j],c = PolC3.T[j],cmap = "coolwarm",vmax = 1, vmin = -1,s = 5)
fig.colorbar(graficaC3)
ax.set_xticks(Kticks)
ax.set_xticklabels(Klabels,fontsize = 20);

fig,ax = plt.subplots(ncols=1,nrows=1,figsize=(4.5,6))
for j in range(nbandsC3):
  graficaC3 = ax.scatter(kenumC3,BandasC3.T[j],c = CCMC3.T[j],cmap = "Reds",vmax = 1, vmin = 0,s = 5)
fig.colorbar(graficaC3)
ax.set_xticks(Kticks)
ax.set_xticklabels(Klabels,fontsize = 20);

fig,ax = plt.subplots(ncols=1,nrows=1,figsize=(4.5,6))
for j in range(nbandsC3):
  graficaC3 = ax.scatter(kenumC3,BandasC3.T[j],c = PzC3.T[j],cmap = "coolwarm",vmax = 0.1, vmin = -0.1,s = 5)
fig.colorbar(graficaC3)
ax.set_xticks(Kticks)
ax.set_xticklabels(Klabels,fontsize = 20);
/home/deigobau/anaconda3/envs/chiral/lib/python3.12/site-packages/matplotlib/cbook.py:1699: ComplexWarning:

Casting complex values to real discards the imaginary part

/home/deigobau/anaconda3/envs/chiral/lib/python3.12/site-packages/matplotlib/axes/_axes.py:4455: ComplexWarning:

Casting complex values to real discards the imaginary part

Ahora, hacemos el estudio de quiralidad mediante el cálculo del Pseudomomento escalar. Dado un modo \(k\), este está determinado por \[(\sum p^{z}L^{z})_{k} = -(\omega_{k})^{2}\left[\sum_{i}m_{i}c^{z}_{ki}\left(x_{i}c^{y}_{k,i} - y_{i}c^{x}_{k,i}\right)\right].\] Debajo, se define una función que calcula el valor del escalar de pseudomomento para cada valor de \(k\).

## Animación de modos normales

def Animacion(k,n,num = 4):

    ωchirl,Eigenvectors = EigenfrequenciesC3(k)

    ωchirl = ωchirl[n]
    Eigenvectors = Eigenvectors[:,n]

    A = 0.5

    """NX,NY,NZ = meshgrid( range(-num + 1,num),range(-num+1,num),range(-num+1,num))
    NX = NX.flatten()
    NY = NY.flatten()
    NZ = NZ.flatten()
    NNs = column_stack([NX,NY,NZ])"""
    NZ = array( range(-num + 1,num))  
    NNs = column_stack([NZ])
    NZ = NZ.flatten()
    NNs = column_stack([NZ])
    avecs1 = [avec]
    xr,yr,zr = dot( NNs,avecs1 ).T   
    xeq1,yeq1,zeq1 = dot( NNs,avecs1 ).T + + kron(r1,ones(((2*num-1),1))).T
    xeq2,yeq2,zeq2 = dot( NNs,avecs1 ).T + kron(r2,ones(((2*num-1),1))).T
    xeq3,yeq3,zeq3 = dot( NNs,avecs1 ).T + kron(r3,ones(((2*num-1),1))).T

    R = array([xr,yr,zr]).T

    if ωchirl < 10E-3:
        T      = 10
    else: 
        T = 2*pi/ωchirl # periodo
        
    veces  = 5       # número de periodos


    # Posición en el tiempo cero
    t0  = 0
    u10 = A*exp(-1J*ωchirl*t0+1J*dot(R,array([0,0,k])))
    x10 = xeq1 + Eigenvectors[0]*u10
    y10 = yeq1 + Eigenvectors[1]*u10
    z10 = zeq1 + Eigenvectors[2]*u10
    x20 = xeq2 + Eigenvectors[3]*u10
    y20 = yeq2 + Eigenvectors[4]*u10
    z20 = zeq2 + Eigenvectors[5]*u10
    x30 = xeq3 + Eigenvectors[6]*u10
    y30 = yeq3 + Eigenvectors[7]*u10
    z30 = zeq3 + Eigenvectors[8]*u10


    time   = linspace(t0,veces*T,endpoint=False)


    Frames = []
    for t in time:
        u1 = A*exp(-1J*ωchirl*t+1J*dot(R,array([0,0,k])))
        x1 = xeq1 + Eigenvectors[0]*u1
        y1 = yeq1 + Eigenvectors[1]*u1
        z1 = zeq1 + Eigenvectors[2]*u1
        x2 = xeq2 + Eigenvectors[3]*u1
        y2 = yeq2 + Eigenvectors[4]*u1
        z2 = zeq2 + Eigenvectors[5]*u1
        x3 = xeq3 + Eigenvectors[6]*u1
        y3 = yeq3 + Eigenvectors[7]*u1
        z3 = zeq3 + Eigenvectors[8]*u1
        Frames.append( go.Frame(data=[ go.Scatter3d(x=x1.real,
                                                y=y1.real,
                                                z=z1.real,
                                                mode="markers",
                                                marker=dict(color="blue",size=5),
                                                name=f'time = {t:.2f}'),
                                    go.Scatter3d(x=x2.real,
                                                y=y2.real,
                                                z=z2.real,
                                                mode="markers",
                                                marker=dict(color="blue",size=5),
                                                name=f'time = {t:.2f}'),
                                   go.Scatter3d(x=x3.real,
                                                y=y3.real,
                                                z=z3.real,
                                                mode="markers",
                                                marker=dict(color="blue",size=5),
                                                name=f'time = {t:.2f}')             ]) )


    fig = go.Figure(
        data=[ go.Scatter3d(x=x10.real,
                                                y=y10.real,
                                                z=z10.real,
                                                mode="markers",
                                                marker=dict(color="blue",size=5),
                                                name=f'time = {t:.2f}'),
                                    go.Scatter3d(x=x20.real,
                                                y=y20.real,
                                                z=z20.real,
                                                mode="markers",
                                                marker=dict(color="blue",size=5),
                                                name=f'time = {t:.2f}'),
                                   go.Scatter3d(x=x30.real,
                                                y=y30.real,
                                                z=z30.real,
                                                mode="markers",
                                                marker=dict(color="blue",size=5),
                                                name=f'time = {t:.2f}')             ],
        frames = Frames
    )

    fig.update_layout(xaxis= dict(range=[-0.5, 0.5], autorange=False),
                        yaxis= dict(range=[-0.5, 0.5], autorange=False),
                        scene={
                        'xaxis': {'range': [-5.2*num, 5.2*num], 'rangemode': 'tozero', 'tickmode': "linear", 'tick0': -5, 'dtick': 1},
                        'yaxis': {'range': [-5.2*num, 5.2*num], 'rangemode': 'tozero', 'tickmode': "linear", 'tick0': -5, 'dtick': 1},
                        'zaxis': {'range': [-5.2*num, 5.2*num], 'rangemode': 'tozero', 'tickmode': "linear", 'tick0': -5, 'dtick': 1},
                        'aspectratio': {
                            'x': 1,
                            'y': 1,
                            'z': 1,                       }},
                        showlegend=True,
                        title="Start Title",
                        updatemenus=[dict(type    = "buttons",
                                            buttons = [dict(label="Play",
                                                            method  = "animate",
                                                            args    = [None,
                                                                        dict(frame       = dict(duration=100,redraw=True), 
                                                                            transition  = dict(duration=100),
                                                                            fromcurrent = True,
                                                                            mode        = 'immediate')])])]),

    fig.show()
Animacion(-0.05,5,1)
#Animacion(0.5,5,2)
Animacion(0.05,5,1)
kplot = 0.5*pi/c
nband = 0

r0 = positions.reshape((9,))
A = 2

def rt(t,k,nband):

  ωchirl,Eigenvectors = EigenfrequenciesC3(k)

  ωchirl = ωchirl[int(nband)]
  Eigenvectors = Eigenvectors[:,nband]

  rt = (r0 + A*Eigenvectors*exp(-1J*ωchirl*t)).real

  r1 = rt[:3]
  r2 = rt[3:6]
  r3 = rt[6:]

  return r1,r2,r3
ωchirl,Eigenvectors = EigenfrequenciesC3(kplot)
ωchirl = ωchirl[nband]

periodo = 2*pi/ωchirl

t = linspace(0,periodo,500)
R = array(list(map(rt,t,itertools.repeat(kplot),itertools.repeat(nband))))

X1,Y1,Z1 = R[:,0].T
X2,Y2,Z2 = R[:,1].T
X3,Y3,Z3 = R[:,2].T

fig,ax = plt.subplots(ncols=1,nrows=1,figsize=(6,6))

ax.scatter(X1,Y1,c = t,cmap = "Blues",vmax = periodo, vmin = 0,s = 2*A)
ax.scatter(X2,Y2,c = t,cmap = "Reds",vmax = periodo, vmin = 0,s = 2*A)
ax.scatter(X3,Y3,c = t,cmap = "Greens",vmax = periodo, vmin = 0,s = 2*A)

cmap1 = matplotlib.cm.get_cmap('Blues')
cmap2 = matplotlib.cm.get_cmap('Reds')
cmap3 = matplotlib.cm.get_cmap('Greens')

rgba1 = cmap1(periodo)
rgba2 = cmap2(periodo)
rgba3 = cmap3(periodo)

ax.arrow(X1[0],Y1[0],(X1[1]-X1[0])*0.01,(Y1[1]-Y1[0])*0.01,head_width = 0.066*A,head_length = 0.1*A,fc = rgba1,ec=rgba1)
ax.arrow(X2[0],Y2[0],(X2[1]-X2[0])*0.01,(Y2[1]-Y2[0])*0.01,head_width = 0.066*A,head_length = 0.1*A,fc = rgba2,ec=rgba2)
ax.arrow(X3[0],Y3[0],(X3[1]-X3[0])*0.01,(Y3[1]-Y3[0])*0.01,head_width = 0.066*A,head_length = 0.1*A,fc = rgba3,ec=rgba3)

ax.set_ylabel("y",fontsize = 20)
ax.set_xlabel("x",fontsize = 20)
/tmp/ipykernel_42974/1567948512.py:19: MatplotlibDeprecationWarning:

The get_cmap function was deprecated in Matplotlib 3.7 and will be removed two minor releases later. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap(obj)`` instead.

/tmp/ipykernel_42974/1567948512.py:20: MatplotlibDeprecationWarning:

The get_cmap function was deprecated in Matplotlib 3.7 and will be removed two minor releases later. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap(obj)`` instead.

/tmp/ipykernel_42974/1567948512.py:21: MatplotlibDeprecationWarning:

The get_cmap function was deprecated in Matplotlib 3.7 and will be removed two minor releases later. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap(obj)`` instead.
Text(0.5, 0, 'x')

def MovimientoPlano(n):

    ωchirl,Eigenvectors = EigenfrequenciesC3(0)
    ωchirl = ωchirl[n]

    Kpoints = np.linspace(-pi/c,pi/c,500)

    # Movimiento para k distinto de cero

    ωchirl,Eigenvectors = EigenfrequenciesC3(0)
    ωchirl = ωchirl[n]

    periodo = 2*pi/ωchirl

    t = linspace(0,periodo,200)

    R = array(list(map(rt,t,itertools.repeat(0),itertools.repeat(n))))

    X10,Y10,Z10 = R[:,0].T
    X20,Y20,Z20 = R[:,1].T
    X30,Y30,Z30 = R[:,2].T

    

    # Posición para k distinto de cero 

    Frames = []
    for k in Kpoints:

        ωchirl,Eigenvectors = EigenfrequenciesC3(k)
        ωchirl = ωchirl[n]

        periodo = 2*pi/ωchirl
        t = linspace(0,periodo,200)

        Rk = array(list(map(rt,t,itertools.repeat(k),itertools.repeat(n))))

        X1,Y1,Z1 = Rk[:,0].T
        X2,Y2,Z2 = Rk[:,1].T
        X3,Y3,Z3 = Rk[:,2].T

        Frames.append( go.Frame(data=[ go.Scatter(x=X1,
                                                y=Y1,
                                                mode="markers",
                                                marker=dict(color="blue",size=5),
                                                name=f'time = {k:.2f}'),
                                    go.Scatter(x=X2,
                                                y=Y2,
                                                mode="markers",
                                                marker=dict(color="red",size=5),
                                                name=f'time = {k:.2f}'),
                                   go.Scatter(x=X3.real,
                                                y=Y3.real,
                                                mode="markers",
                                                marker=dict(color="green",size=5),
                                                name=f'time = {k:.2f}')             ]) )


    fig = go.Figure(
        data=[ go.Scatter3d(x=X10.real,
                                                y=Y10.real,
                                                mode="markers",
                                                marker=dict(color="blue",size=5),
                                                name=f'time = {k:.2f}'),
                                    go.Scatter3d(x=X20.real,
                                                y=Y20.real,
                                                mode="markers",
                                                marker=dict(color="red",size=5),
                                                name=f'time = {k:.2f}'),
                                   go.Scatter3d(x=X30.real,
                                                y=Y30.real,
                                                mode="markers",
                                                marker=dict(color="blue",size=5),
                                                name=f'time = {k:.2f}')             ],
        frames = Frames
    )

    fig.update_layout(xaxis= dict(range=[-2., 2.], autorange=False),
                        yaxis= dict(range=[-2., 2.], autorange=False),
                        showlegend=True,
                        title="Start Title",
                        updatemenus=[dict(type    = "buttons",
                                            buttons = [dict(label="Play",
                                                            method  = "animate",
                                                            args    = [None,
                                                                        dict(frame       = dict(duration=100,redraw=True), 
                                                                            transition  = dict(duration=100),
                                                                            fromcurrent = True,
                                                                            mode        = 'immediate')])])]),

    fig.show()
MovimientoPlano(4)
def MovPlano(n):
  fig = go.Figure()

  Kpoints = np.linspace(-pi/c,pi/c,500)

  # Add traces, one for each slider step
  for k in Kpoints:
      ωchirl,Eigenvectors = EigenfrequenciesC3(k)
      ωchirl = ωchirl[n]

      periodo = 2*pi/ωchirl
      t = linspace(0,periodo,200)

      Rk = array(list(map(rt,t,itertools.repeat(k),itertools.repeat(n))))

      X1,Y1,Z1 = Rk[:,0].T
      X2,Y2,Z2 = Rk[:,1].T
      X3,Y3,Z3 = Rk[:,2].T

      X = [X1,X2,X3]
      Y = [Y1,Y2,Y3]
    
      fig.add_trace(
            go.Scatter(
                visible=False,
                line=dict(color="blue", width=6),
                name="K = " + str(k),
                x=X1,
                y=Y1))
      fig.add_trace(
            go.Scatter(
                visible=False,
                line=dict(color="red", width=6),
                name="K = " + str(k),
                x=X2,
                y=Y2))
      fig.add_trace(
            go.Scatter(
                visible=False,
                line=dict(color="green", width=6),
                name="K = " + str(k),
                x=X3,
                y=Y3))

  fig.data[10].visible = True
  # Create and add slider
  steps = []
  for i in range(0,len(fig.data),3):
      step = dict(
          method="update",
          args=[{"visible": [False] * len(fig.data)},
                {"title": "Slider switched to step: " + str(i)}],  # layout attribute
      )
      step["args"][0]["visible"][i:i+3] = [True,True,True]  # Toggle i'th trace to "visible"
      steps.append(step)

  sliders = [dict(
      active=10,
      currentvalue={"prefix": "Frequency: "},
      pad={"t": 50},
      steps=steps
  )]

  fig.update_layout(
      sliders=sliders
  )

  fig.show()
MovPlano(4)